package com.adcc.loadsheet.billing.security;

import com.adcc.loadsheet.billing.configuration.SystemConfig;
import com.adcc.aoc.devLib.common.log.Log;
import com.google.common.base.Strings;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 校验head是否有token的校验器
 * Created by zhaoml on 2020-04-01.
 */
public class TokenCheckFilter extends BasicAuthenticationFilter {

    @Autowired
    private SystemConfig systemConfig;

    @Autowired
    private JWTFactory jwtFactory;

    @Autowired
    BillingUserDetailesService billingUserDetailesService;

    /**
     * 构造函数
     * @param authenticationManager
     */
    public TokenCheckFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    /**
     * 解析Token
     * @param token
     * @return
     */
    private UsernamePasswordAuthenticationToken parseToken(String token){
        try{
            token = token.replace(systemConfig.getTokenPrefix(),"");
            BillingUserToken sct = jwtFactory.decode(token);
            if(sct != null && !Strings.isNullOrEmpty(sct.getBody())){
                if(sct.getExpiredTime().isBefore(new DateTime(DateTimeZone.UTC).toLocalDateTime().toDateTime())){
                    return null;
                }
                UserInfo userInfo = new UserInfo();
                userInfo.setUsername(sct.getBody());
                BillingUserDetails billingUserDetails = (BillingUserDetails)billingUserDetailesService.loadUserByUsername(userInfo.getUsername());
                return new UsernamePasswordAuthenticationToken(billingUserDetails,null,billingUserDetails.getAuthorities());
            }else {
                return null;
            }
        }catch (Exception ex){
            Log.error(TokenCheckFilter.class, "解析Token出错", ex);
            return null;
        }
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        try{
            String cookie = request.getHeader("Cookie");
            if (cookie == null) {
                chain.doFilter(request, response);
                return;
            }
            String[] cookies = cookie.split("; ");
            for (String str : cookies) {
                String[] key_value = str.split("=");
                //如果数组长度为2（防止由于前台将cookie值置为空导致的数组下标越界）并且key为token时，取其值
                if (key_value.length == 2 && "loadsheetbilltoken".equals(key_value[0])) {
                    cookie = key_value[1];
                    break;
                }
            }
            if(Strings.isNullOrEmpty(cookie) || !cookie.startsWith(systemConfig.getTokenPrefix())){
                Log.debug(TokenCheckFilter.class,"token is invalid");
                chain.doFilter(request,response);
                return;
            }else{
                UsernamePasswordAuthenticationToken authenticationToken = parseToken(cookie);
                if(authenticationToken == null){
                    Log.debug(TokenCheckFilter.class,"token is fake");
                    chain.doFilter(request,response);
                    return;
                }else
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            }
            super.doFilterInternal(request, response, chain);
        }catch (Exception ex){
            Log.error(TokenCheckFilter.class, "解析Token出错", ex);
        }
    }
}